#include "SceneState.h"


SceneState::SceneState(string name)
{
	lock = new CriticalSection();
	this->name = name;

}

SceneState::~SceneState(void)
{
	LISTOBJSTA::iterator it;
	for (it=objectsState.begin(); it!=objectsState.end(); it++)
	{
		delete (*it);
	}
	delete lock;
}

void SceneState::updateState(SceneObjectState* objectState)
{
	lock->adquire();

	LISTOBJSTA::iterator it;
	it = objectsState.begin();
	bool foundObject =false; 
	while(!foundObject && it != this->objectsState.end()){
		if ((*it)->getType() == TANK && (*it)->getId() == objectState->getId() ){
			(*it)->setX(objectState->getX());
			(*it)->setY(objectState->getY());
			(*it)->setAngle(objectState->getAngle());		
			foundObject =true;
		}
		it++;
	}
	if (foundObject)
		notifyObservers();
	lock->release();
}


string SceneState::getSceneName(){
	return this->name;
}

list<SceneObjectState*>* SceneState::getObjectsState()
{
	return &(this->objectsState);
}

void SceneState::loadSceneBox()
{
	Scene* tempScene =new Scene(28,26,getSceneName());
	SceneStateRepository* sceneRepo = new SceneStateRepository();
	try
	{
		sceneRepo->load(getSceneName(),tempScene);
		this->backgroundPath= tempScene->getBackgroundPath();
		cout << "[INFO] Escenario cargado: " << tempScene->getName() << endl;
		list<SceneObject*>::iterator it;
		it = tempScene->getObjsLst()->begin();
		while(it!=tempScene->getObjsLst()->end()){
			SceneObjectState* newObjState = new SceneObjectState("SceneObject");
			newObjState->setType((*it)->getType());
			newObjState->setX((*it)->getXCoordinate());
			newObjState->setY((*it)->getYCoordinate());
			newObjState->setObjName((*it)->getName());
			this->objectsState.push_back(newObjState);
			it++;
		}

		delete sceneRepo;
		delete tempScene;
	}
	catch (PersistenceException& pe)
	{
		pe.getMessage();
		delete sceneRepo;
		delete tempScene;
	}
}

void SceneState::updateBulletDeath(SceneObjectState* so){
	lock->adquire();
	LISTOBJSTA::iterator it;
	it = objectsState.begin();
	bool foundObject =false; 
	while(!foundObject && it != this->objectsState.end()){
		if ((*it)->getType() == BULLET && (*it)->getId() == so->getId() ){
			LISTOBJSTA::iterator auxIt = it;
			it++;
			delete (*auxIt);
			this->objectsState.erase(auxIt);
			foundObject =true;
		}else
			it++;
	}
	if (foundObject)
	{	
		notifyObservers();
	}
	lock->release();
	delete so;

}

void SceneState::updateNewBullet(SceneObjectState* so){
	lock->adquire();
	this->objectsState.push_back(so);
	notifyObservers();
	lock->release();
}

void SceneState::updateNewTank(SceneObjectState* so){
	lock->adquire();
	this->objectsState.push_back(so);
	notifyObservers();
	lock->release();
}

void SceneState::updateTankOff(SceneObjectState* so){
	lock->adquire();
	LISTOBJSTA::iterator it;
	it = objectsState.begin();
	bool foundObject =false; 
	while(!foundObject && it != this->objectsState.end()){
		if ((*it)->getType() == TANK && (*it)->getId() == so->getId() ){
			LISTOBJSTA::iterator auxIt = it;
			it++;
			delete (*auxIt);
			this->objectsState.erase(auxIt);
			foundObject =true;
		}else
			it++;
	}
	if (foundObject)
	{	
		notifyObservers();
	}
	lock->release();
	delete so;
}

string SceneState::getBackgroundPath(){
	return this->backgroundPath;
}



ByteBuffer* SceneState::marshal(void)
{
	ByteBuffer* buffer = new ByteBuffer();
	list<SceneObjectState*>::iterator it = this->getObjectsState()->begin();
	int code = 0;
	while(it != this->getObjectsState()->end())
	{	
		switch((*it)->getType())
		{
			case TANK:
				{ code = 5;
				}break;

			case BULLET:
				{code =2;
				}break;

			case SCENEOBJECT:
				{code = 6;
				}break;
		}
		buffer->put("|code=");
		buffer->put(code);
		buffer->put("|name=");
		buffer->put((*it)->getObjName());
		buffer->put("|id=");
		buffer->put((*it)->getId());	
		buffer->put("|angle=");
		buffer->put((*it)->getAngle());
		buffer->put("|xpos=");
		buffer->put((*it)->getX());
		buffer->put("|ypos=");
		buffer->put((*it)->getY());
		buffer->put("|");
		it++;
	}
	return buffer;
}

void SceneState::unmarshal(ByteBuffer* buffer)
{
	string temp(buffer->get());
	string temp2 = temp.substr(0, buffer->size());
	string token;
	string key;
	string value;
	size_t found;
	int index = 0;
	Tokenizer tokenizer(temp2, "|");
	SceneObjectState* newObj =NULL;
	while (tokenizer.nextToken())
	{
		
        token = tokenizer.getToken();
		found = token.find("=", 0);
		if (found != string::npos)
		{
			key = token.substr(0, found);
			value = token.substr(found+1, token.length()-key.length()+1);

			if (key == "code")
			{
				newObj = new SceneObjectState();
				newObj->setCode(atoi(value.c_str()));
			}
			else if (key == "name")
			{
				newObj->setObjName(value);
			}
			else if (key == "id")
			{
				newObj->setId(atoi(value.c_str()));
			}
			else if (key == "angle")
			{
				newObj->setAngle(atoi(value.c_str()));
			}
			else if (key == "xpos")
			{
				newObj->setX(atoi(value.c_str()));
			}
			else if (key == "ypos")
			{
				newObj->setY(atoi(value.c_str()));
				this->getObjectsState()->push_back(newObj);				
			}
		}
	}
}